using System;
using System.Management;
using System.Globalization;

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;

using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace CSharpDistilled.Diagnostics
{
    /// <summary>
    /// Represents a physical graphics processor or graphics processor core.
    /// </summary>
    public sealed class GraphicsProcessor : Device
    {
        #region GraphicsProcessor Private Fields

        private long m_memory;

        private Version m_driverVersion;

        #endregion

        #region private GraphicsProcessor()

        /// <summary>
        /// Initializes a new instance of the <see cref="T:GraphicsProcessor"/> class.    
        /// </summary>
        private GraphicsProcessor()
        {

        }

        #endregion

        #region public static IList<GraphicsProcessor> GetGraphicsProcessors()

        /// <summary>
        /// Gets an <see cref="T:System.Collections.Generic.IList`1"/> containin a <see cref="T:GraphicsProcessor"/> instance for each physical graphics processor or graphics processor core.
        /// </summary>
        /// <remarks>
        /// The <see cref="M:GraphicsProcessor.GetGraphicsProcessors"/> method is implemented as a method and not a property because the list of graphics processors will take considerably longer
        /// to retrieve than a simple field. Static code analysis warning CA1024 is therefore suppressed after consulting the .NET Framework Design Guidelines written by Brad Abrams and 
        /// Krzysztof Cwalina which is published by Addison Wesley.
        /// </remarks>
        /// <returns>An <see cref="T:System.Collections.Generic.IList`1"/> containin a <see cref="T:GraphicsProcessor"/> instance for each physical graphics processor or graphics processor core.</returns>
        [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
        public static IList<GraphicsProcessor> GetGraphicsProcessors()
        {
            try
            {
                List<GraphicsProcessor> processors = new List<GraphicsProcessor>();

                ManagementObjectSearcher searcher = new ManagementObjectSearcher(@"root\CIMV2", "SELECT * FROM Win32_VideoController");

                foreach (ManagementObject managementObject in searcher.Get())
                {
                    GraphicsProcessor processor = new GraphicsProcessor();

                    processor.Name = managementObject["Name"] as string;
                    processor.Description = managementObject["Description"] as string;
                    processor.DeviceId = managementObject["DeviceID"] as string;

                    processor.Memory = Convert.ToInt64(managementObject["AdapterRAM"], CultureInfo.CurrentCulture);

                    string version = managementObject["DriverVersion"] as string;

                    if (!string.IsNullOrEmpty(version))
                    {
                        processor.DriverVersion = new Version(version);
                    }

                    processors.Add(processor);
                }

                return new ReadOnlyCollection<GraphicsProcessor>(processors);
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message);
                Trace.WriteLine(ex.StackTrace);

                throw;
            }
        } 

        #endregion

        #region public long public int Memory

        /// <summary>
        /// Gets or sets the amount of random access memory installed for the graphics processor in bytes.
        /// </summary>
        /// <value>The amount of random access memory installed for the graphics processor in bytes.</value>
        public long Memory
        {
            get
            {
                return m_memory;
            }
            private set
            {
                m_memory = value;
            }
        }

        #endregion

        #region public Version DriverVersion

        /// <summary>
        /// Gets or sets the version of the device driver for the graphics processor.
        /// </summary>
        /// <value>The version of the device driver for the graphics processor.</value>
        public Version DriverVersion
        {
            get
            {
                return m_driverVersion;
            }
            private set
            {
                m_driverVersion = value;
            }
        } 

        #endregion
    }
}
